use crate::protocol::type_schema::TypeSchema;
use crate::protocol::task::{SymbolicTask, NominalTask};
use crate::error::ServerError;
use nom::{
    branch::alt,
    bytes::complete::{tag, take_until},
    character::complete::{alpha1, alphanumeric1, char, multispace0},
    combinator::{map, opt, recognize},
    multi::{many0, separated_list0},
    sequence::{delimited, pair, preceded, separated_pair, terminated},
    IResult, Parser,
};

impl SymbolicTask {
    pub fn try_parse_loose(signature: &NominalTask) -> Result<Self, ServerError> {
        task_nominal_to_symbolic(signature)
    }

    pub fn parse_loose(task: &NominalTask) -> Self {
        match SymbolicTask::try_parse_loose(task) {
            Ok(task) => task,
            Err(e) => panic!("Failed to parse task signature: {}", task),
        }
    }
}

impl TypeSchema {
    pub fn try_parse_loose(input: &str) -> Result<Self, ServerError> {
        parse_abs_type(input)
    }
    pub fn parse_loose(input: &str) -> Self {
        match TypeSchema::try_parse_loose(input) {
            Ok(task) => task,
            Err(e) => panic!("Failed to parse typeschema: {}", input),
        }
    }
}

pub fn task_nominal_to_symbolic(task: &NominalTask) -> Result<SymbolicTask, ServerError> {
    let mut task_str = task.clone();
    task_str = task_str.replace(' ', "");
    let mut splits = task_str.split(':');
    if let (Some(name), Some(tpe), None) = (splits.next(), splits.next(), splits.next()) {
        let mut splits2 = tpe.split("->");
        if let (Some(tin), Some(tout), None) = (splits2.next(), splits2.next(), splits2.next()) {
            let stin = parse_tpe(tin)?;
            let stout = parse_tpe(tout)?;
            return Ok(SymbolicTask::new(name.into(), stin, stout))
        }
        else {
            return Err(ServerError::WorkflowError(format!("任务签名不能正确分割箭头: {}", task)));
        }
    }
    Err(ServerError::WorkflowError(format!("任务签名不能正确分割冒号: {}", task)))
}

fn parse_tpe(tpe: &str) -> Result<TypeSchema, ServerError> {
    entry(tpe).map(|x|x.1).map_err(|_|ServerError::WorkflowError(format!("TypeSchema解析错误: {}", tpe)))
}

fn basic_type(input: &str) -> IResult<&str, TypeSchema> {
    alt((
        tag("Void").or(tag("void")).map(|_| TypeSchema::Void),
        tag("Int").or(tag("int")).map(|_| TypeSchema::Int),
        tag("Float").or(tag("float")).map(|_| TypeSchema::Float),
        tag("Str").or(tag("str")).map(|_| TypeSchema::Str),
        tag("Bool").or(tag("bool")).map(|_| TypeSchema::Bool),
        tag("Json").or(tag("json")).map(|_| TypeSchema::Json),
    )).parse(input)
}

fn list_type(i: &str) -> IResult<&str, TypeSchema> {
    let (i, _) = tag("List<").or(tag("list<")).parse(i)?;
    let (i, t) = entry(i)?;
    let (i, _) = tag(">")(i)?;
    Ok((i, TypeSchema::List(Box::new(t))))
}

fn list_type_loose(i: &str) -> IResult<&str, TypeSchema> {
    let (i, _) = tag("[")(i)?;
    let (i, t) = entry(i)?;
    let (i, _) = tag("]")(i)?;
    Ok((i, TypeSchema::List(Box::new(t))))
}

fn map_type(i: &str) -> IResult<&str, TypeSchema> {
    let (i, _) = tag("Map<").or(tag("map<")).parse(i)?;
    let (i, k) = entry(i)?;
    let (i, _) = tag(",")(i)?;
    let (i, v) = entry(i)?;
    let (i, _) = tag(">")(i)?;
    Ok((i, TypeSchema::Map(Box::new(k), Box::new(v))))
}

fn map_type_loose(i: &str) -> IResult<&str, TypeSchema> {
    let (i, _) = tag("{")(i)?;
    let (i, k) = entry(i)?;
    let (i, _) = tag(",")(i)?;
    let (i, v) = entry(i)?;
    let (i, _) = tag("}")(i)?;
    Ok((i, TypeSchema::Map(Box::new(k), Box::new(v))))
}

fn option_type(i: &str) -> IResult<&str, TypeSchema> {
    let (i, _) = tag("?")(i)?;
    let (i, t) = entry(i)?;
    Ok((i, TypeSchema::Opt(Box::new(t))))
}

fn option_type_loose(i: &str) -> IResult<&str, TypeSchema> {
    let (i, _) = tag("option<").or(tag("Option<")).parse(i)?;
    let (i, t) = entry(i)?;
    let (i, _) = tag(">")(i)?;
    Ok((i, TypeSchema::Opt(Box::new(t))))
}

fn tuple_type(input: &str) -> IResult<&str, TypeSchema> {
    map(
        delimited(
            char('('),
            separated_list0(
                tag(","),
                entry
            ),
            char(')')
        ),
        |types| TypeSchema::Tuple(types)
    ).parse(input)
}

fn tuple_type_loose(input: &str) -> IResult<&str, TypeSchema> {
    map(
        delimited(
            tag("Tuple<").or(tag("tuple<")),
            separated_list0(
                tag(","),
                entry
            ),
            tag(">")
        ),
        |types| TypeSchema::Tuple(types)
    ).parse(input)
}

macro_rules! nom_error {
    ($input:expr) => {
        Err(nom::Err::Error(nom::error::Error::new($input, nom::error::ErrorKind::Tag)))
    };
}

fn ident(i: &str) -> IResult<&str, &str> {
    recognize(pair(
        alpha1,
        many0(alt((alphanumeric1, tag("_"))))
    )).parse(i)
}

fn custom_type(i: &str) -> IResult<&str, TypeSchema> {
    let (ii, name) = ident(i)?;
    match name {
        "List" | "Map" | "Tuple" | "Option" | "list" | "map" | "tuple" | "option" => nom_error!(i), // 自定义类型不能是List, Map, Tuple, Option, list, map, tuple, option
        _ => Ok((ii, TypeSchema::DataType(name.into())))
    }
}

fn entry(input: &str) -> IResult<&str, TypeSchema> {
    alt((
        basic_type,
        list_type,
        list_type_loose,
        map_type,
        map_type_loose,
        tuple_type,
        tuple_type_loose,
        option_type,
        option_type_loose,
        custom_type
    )).parse(input)
}

pub fn parse_abs_type(input: &str) -> Result<TypeSchema, ServerError> {
    entry(input).map(|x|x.1).map_err(|_|ServerError::WorkflowError(format!("TypeSchema解析错误: {}", input)))
}


#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn usage() {
        let tasks = vec![
            "main:FilePath->Map<String,List<List<(PointF,Float)>>>",
            "t:Option<A>->B"
        ];
        for nominal in tasks.iter() {
            let symbolic = task_nominal_to_symbolic(&nominal.to_string());
            println!("{:?}", symbolic);
            assert!(symbolic.is_ok());
        }
    }
}